/*******************************************************************
 *
 * Copyright (C), 2021-2022, Letstrong, All rights reserved.
 *
 * Author      : 
 * Create Time : 2021-01-04
 * Version     : v0.1
 * Description : 
 *******************************************************************/
 
/*----------------------------Head file----------------------------*/
#include "user_config.h"

#if(ROPE_CENTRAL_SUP_ENABLE)

#include "hal_utc.h"
#include "sys_task.h"
#include "central.h"
#include "central_task.h"
#include "sw_timer_task.h"
#include "app_skip_alg.h"
#include "app_store_mem.h"
#include "app_global_data.h"
#include "app_store_set_info.h"
#include "central_protocol.h"
#include "user_protocol.h"

/*----------------------------macro file---------------------------*/
#define CENTRAL_PROTO_LOG_EN		1

#if CENTRAL_PROTO_LOG_EN
#include "log.h"
#define CENTRAL_PROTO_LOG			LOG_DEBUG
#else
#define CENTRAL_PROTO_LOG(...)
#endif

#define app_sync_system_time		hal_utc_seconds_set

/*----------------------------type define--------------------------*/

/*----------------------------var define---------------------------*/
static uint8_t resend_cnt = 0;
struct central_ind_upd_req indic;

/*-------------------------func declaration------------------------*/

/*-----------------------------------------------------------------*/

static uint8_t checksum(const uint8_t* pData, uint8_t len)
{
	uint8_t chksum = 0;
	for(uint8_t i=0;i<len;i++) {
		chksum += pData[i];
	}
	return chksum;
}


void dev_upload_resend_to_rope_central(void)
{
	resend_cnt++;
	if(resend_cnt < 3) {
		ble_resend_timer_start(1000);
		central_indicate_data(&indic);
	}
}

static bool central_trans_upload(uint8_t cmd, const uint8_t* pData, uint16_t len, bool resend_enable)
{
	if(len > APP_FRAME_DATA_MAX_SIZE)
		return false;

	indic.len = APP_PAYLOAD_MAX_SIZE;
	indic.value[OFFSETOF(app_trans_t, id1)] = PRO_VER_B1;
	indic.value[OFFSETOF(app_trans_t, id2)] = PRO_VER_B2;
	indic.value[OFFSETOF(app_trans_t, cmd)] = cmd;
	memcpy(&indic.value[OFFSETOF(app_trans_t, data)], pData, len);
	indic.value[OFFSETOF(app_trans_t, crc)] = checksum(&indic.value[OFFSETOF(app_trans_t, cmd)], len + 1);

	central_indicate_data(&indic);
	return true;
}


void dev_upload_batt_per_to_rope_central(void)
{
	if(BLE_CONN_TYPE_ROPE_CENTRAL != g_app_data.sys.ble_conn_type)
		return;

	uint8_t tx_data[APP_FRAME_DATA_MAX_SIZE];

	memset(tx_data, 0, sizeof(tx_data));

	tx_data[0] = 0;
	tx_data[1] = g_app_data.batt.disp_percent;

	central_trans_upload(ROPE_CMD_BAT_PER, tx_data, sizeof(tx_data), false);
}

void dev_upload_jump_disp_data_to_rope_central(void)
{
	if(BLE_CONN_TYPE_ROPE_CENTRAL != g_app_data.sys.ble_conn_type)
		return;
	
	if(g_app_data.tmp.skip.skip_cnt_sum <= 0)
		return;
	
	uint8_t tx_data[APP_FRAME_DATA_MAX_SIZE];
	uint8_t jump_mode = g_app_data.tmp.jump.mode;
	
	memset(tx_data, 0, sizeof(tx_data));
	
	tx_data[0] = jump_mode;
	if(SKIP_MODE_TIME == jump_mode) {
		uint16_t secs_set = Tranverse16(g_app_data.user.cnt_down_secs);
		memcpy(&tx_data[1], (uint8_t*)&secs_set, sizeof(secs_set));
	}
	else if(SKIP_MODE_COUNT == jump_mode) {
		uint16_t jump_set = Tranverse16(g_app_data.user.cnt_down_jumps);
		memcpy(&tx_data[1], (uint8_t*)&jump_set, sizeof(jump_set));
	}
	uint16_t used_secs = Tranverse16(g_app_data.tmp.jump.used_sec);
	uint16_t jmp_cnt = Tranverse16(g_app_data.tmp.jump.jump_cnt);
	memcpy(&tx_data[3], (uint8_t*)&used_secs, sizeof(used_secs));
	memcpy(&tx_data[5], (uint8_t*)&jmp_cnt, sizeof(jmp_cnt));
	tx_data[7] = g_app_data.tmp.jump.conti_valid_num;
	
	tx_data[15] = g_app_data.batt.disp_percent;

	central_trans_upload(ROPE_CMD_DISP_DATA, tx_data, sizeof(tx_data), false);
}


void dev_upload_last_jump_data_to_rope_central(void)
{
	if(BLE_CONN_TYPE_ROPE_CENTRAL != g_app_data.sys.ble_conn_type)
		return;
	
	if(false == g_app_data.sys.state.tx_to_central)
		return;
	
	skip_packet_t skip_pack;
	uint8_t tx_data[APP_FRAME_DATA_MAX_SIZE];
	
	memset(tx_data, 0, sizeof(tx_data));
	app_mem_latest_skip_ret_read((uint8_t*)&skip_pack, sizeof(skip_pack));
	
	uint32_t utc = Tranverse32(skip_pack.start_utc); //Prevent structure align not same and make system crash.
	memcpy(tx_data, (uint8_t*)&utc, sizeof(utc));
	tx_data[4] = skip_pack.mode;
	if(SKIP_MODE_TIME == skip_pack.mode) {
		uint16_t secs_set = Tranverse16(g_app_data.user.cnt_down_secs); 
		memcpy(&tx_data[5], (uint8_t*)&secs_set, sizeof(secs_set));
	}
	else if(SKIP_MODE_COUNT == skip_pack.mode) {
		uint16_t jump_set = Tranverse16(g_app_data.user.cnt_down_jumps);
		memcpy(&tx_data[5], (uint8_t*)&jump_set, sizeof(jump_set));
	}
	
	uint16_t used_sec = Tranverse16(skip_pack.used_sec);
	uint16_t jump_cnt = Tranverse16(skip_pack.jump_cnt);
	memcpy(&tx_data[7], (uint8_t*)&used_sec , sizeof(used_sec));
	memcpy(&tx_data[9], (uint8_t*)&jump_cnt, sizeof(jump_cnt));
	
	uint16_t freq_avg = Tranverse16(skip_pack.freq_avg);
	uint16_t freq_max = Tranverse16(skip_pack.freq_max);
	//ROPE_PROTO_LOG("freq_avg: %d, freq_max: %d.\n", jmp_pack.freq_avg, jmp_pack.freq_max);
	memcpy(&tx_data[11], (uint8_t*)&freq_avg, sizeof(freq_avg));
	memcpy(&tx_data[13], (uint8_t*)&freq_max, sizeof(freq_max));
	tx_data[15] = skip_pack.conti_valid_num;
	central_trans_upload(ROPE_CMD_JUMP_RET, tx_data, sizeof(tx_data), true);
}


void dev_upload_rsp_jump_dev_seq_num_burn(void)
{
	if(BLE_CONN_TYPE_ROPE_CENTRAL != g_app_data.sys.ble_conn_type)
		return;
	
	uint8_t tx_data[APP_FRAME_DATA_MAX_SIZE];
	
	memset(tx_data, 0, sizeof(tx_data));
	tx_data[0] = RSP_CENTRAL_SUCCESS;
	central_trans_upload(ROPE_CMD_BURN_INFO, tx_data, sizeof(tx_data), false);
}


void ble_rope_central_client_write_handle(const uint8_t* pData, uint16_t len)
{
	//CENTRAL_PROTO_LOG("RX Data:");
	//print_hex(data, len);

	if(len != APP_PAYLOAD_MAX_SIZE)
		return;

	app_trans_t rcv;
	memcpy((uint8_t*)&rcv, pData, len);
	
	if(rcv.id1 != PRO_VER_B1 || rcv.id2 != PRO_VER_B2) {
		CENTRAL_PROTO_LOG("Err pro id: %x, %x.\n", rcv.id1, rcv.id2);
	}
	if(rcv.crc != checksum((uint8_t*)&rcv.cmd, len - APP_PACKET_HEAD_SIZE)) {
		CENTRAL_PROTO_LOG("Err chksum: %x, %x.\n", rcv.crc, rcv.cmd);
		return;
	}
	
	switch(rcv.cmd)
	{
		case ROPE_CMD_USER_SET: {
			uint32_t uni_utc = 0;
			uint16_t timezone_min = 0;
			uni_utc = BUILD_UINT32(rcv.data[6], rcv.data[5], rcv.data[4], rcv.data[3]);
			timezone_min = BUILD_UINT16(rcv.data[8], rcv.data[7]);
			app_set_info_local_timezone_save(timezone_min);
			CENTRAL_PROTO_LOG("DL_CMD_SET: %u, %d.\n", uni_utc, timezone_min);
			app_sync_system_time(uni_utc);
			
			uint8_t jmp_mode = rcv.data[0];
			if(jmp_mode > JUMP_MODE_NULL && jmp_mode < JUMP_MODE_MAX) {
				//Save not done jump data firstly.
				if(g_app_data.tmp.jump.jump_cnt > 0 && false == g_app_data.sys.state.jump_done) {
					app_jump_result_calc_and_save();
				}
				
				if(JUMP_MODE_TIME == jmp_mode) {
					uint16_t secs = BUILD_UINT16(rcv.data[2], rcv.data[1]);
					app_set_info_cnt_down_secs_save(secs);
				}
				else if(JUMP_MODE_COUNT == jmp_mode) {
					uint16_t jmp_cnt = BUILD_UINT16(rcv.data[2], rcv.data[1]);
					app_set_info_cnt_jump_num_save(jmp_cnt);
				}
				sys_task_evt_set(SYS_EVT_APP_BASE + jmp_mode);
			}
		} break;
		
		case ROPE_CMD_APP_RSP: {
			CENTRAL_PROTO_LOG("DL_CMD_RSP: %x, %x.\n", rcv.data[0], rcv.data[1]);
			if(0 == rcv.data[0] && (ROPE_CMD_JUMP_RET == rcv.data[1] || ROPE_CMD_JUMP_HISTORY == rcv.data[1])) {	//Get send jump data rsp.
				g_app_data.sys.state.tx_to_central = false;
				ble_resend_timer_stop();
			}
			else if(1 == rcv.data[0] && false == g_app_data.sys.state.jump_done && g_app_data.tmp.jump.jump_cnt > 0) {
				//Ignore the stop cmd from App if jump have done.
				g_app_data.sys.state.jump_done = true;
				sys_task_evt_set(SYS_EVT_JUMP_DONE);
			}
		} break;
		
		case ROPE_CMD_SEARCH_DEV: {
			CENTRAL_PROTO_LOG("ROPE_CMD_SEARCH_DEV\n");
			sys_task_evt_set(SYS_EVT_SEARCH_DEV);
		} break;
		
		default:
			break;
	}
}


#endif		//#if(ROPE_CENTRAL_SUP_ENABLE)
